package collection.mymap.hash;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import org.testng.annotations.Test;
import util.MathUtil;

/**
 *
 * 1 computeIfAbsent
 * 2 computeIfPresent
 * 3
 * 5 根据map的键排序
 * 6 根据map的值排序
 * 7
 * 8 removeIf,删除多个元素的方法
 * 9 验证弱一致性
 *
 */
public class MapAdvanced {

    /**
     *
     */
    @Test
    private void t1() {
        var map = new HashMap<Integer, Integer>();
        map.put(1, 2);
        map.put(2, 3);
        map.put(3, null);
        System.out.println(map);
        // key对应的value为空，会将第二个参数的返回值存入并返回
        Integer i1 = map.computeIfAbsent(3, k -> 5);
        System.out.println(i1);
        System.out.println(map);

        System.out.println("----------------------");
        var map2 = new HashMap<Integer, Integer>();
        // 若key不存在，也会将第二个参数的返回值存入并返回
        Integer i2 = map2.computeIfAbsent(3, k -> 6);
        System.out.println(i2);
        System.out.println(map2);

        // 若key是null
        Integer i3 = map2.computeIfAbsent(null, k -> 7);
        System.out.println(i3);
    }

    /**
     *
     */
    @Test
    private void t2() {
        var map = new HashMap<Integer, Integer>();
        map.put(1, 1);

        map.compute(1, (key, value) -> value - 1);

        System.out.println("原始map " + map);
        // 这里不会编译报错，k1、k2指的是map的key，k2指的是map的value
        map.computeIfPresent(1, (k1, k2) -> {
            System.out.println("第二轮 " + k1 + " " + k2);
            return k1 - k2;
        });


        System.out.println("1 - 1 " + map);

        map.computeIfPresent(1, (k1, k2) -> {
            System.out.println("第二轮 " + k1 + " " + k2);
            return k1 + k2;
        });
        System.out.println(map);

        map.computeIfPresent(1, Integer::sum);
        System.out.println("1 + 1 " + map);
        map.computeIfPresent(1, (k1, k2) -> {
            System.out.println("第三轮 " + k1 + " " + k2);
            return k1 + k2;
        });
    }

    @Test
    private void t4() {
        var map = new HashMap<Integer, Integer>();
        map.put(1, 1);
        System.out.println(map);

        map.compute(1, (key, value) -> value - 1);

        // 如果没有这个键，会直接put
        map.compute(2, (k, v) -> 2);

        // 键对应的值不存在，
        map.compute(3, (k, v) -> v + 1);

//        map.compute(null, (k, v) -> v + 1);

        System.out.println(map);
    }

    @Test
    public void t5() {
        var map = new HashMap<String, Integer>();

        map.put("9", 3);
        map.put("8", 6);
        map.put("1", 0);
        map.put("3", 1);

        System.out.println(map);
        map.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEach(System.out::println);

        var map2 = new HashMap<Integer, Integer>();
        map2.put(900, 1);
        map2.put(800, 1);
        map2.put(100, 1);
        map2.put(300, 1);

        System.out.println(map2);
        map2.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEach(System.out::println);
    }

    @Test
    public void t6() {
        var map = new HashMap<String, Integer>();

        map.put("9", 3);
        map.put("8", 6);
        map.put("1", 0);
        map.put("3", 1);

        System.out.println(map);
        map.entrySet().stream()
            .sorted(Map.Entry.comparingByValue())
            .forEach(System.out::println);

        var map2 = new HashMap<Integer, Integer>();
        map2.put(900, 1);
        map2.put(800, 0);
        map2.put(100, 9);
        map2.put(300, 8);

        System.out.println(map2);
        Comparator<? super Entry<Integer, Integer>> comparator = Entry.comparingByValue();
//        var comparator2 = Comparator.comparing();

        map2.entrySet().stream()
            .sorted(comparator)
            .forEach(System.out::println);
    }

    @Test(invocationCount = 5)
    private void t7() {
        var map = new HashMap<String, Integer>();
        map.put("9", 3);
        map.put("8", 6);
        map.put("1", 0);
        map.put("3", 1);

        String next = map.keySet().iterator().next();
        System.out.println(next);

    }

    /**
     * removeIf是通过entrySet实现的
     */
    @Test
    private void t8() {
        var map = new HashMap<String, Integer>();
        map.put("9", 3);
        map.put("8", 6);
        map.put("1", 0);
        map.put("3", 1);

        System.out.println(map);
        map.entrySet().removeIf(entry -> entry.getKey().equals("1"));
        System.out.println(map);
        map.entrySet().removeIf(entry -> entry.getValue() % 3 == 0);
        System.out.println(map);
    }

    @Test
    public void t9() {
        ReentrantLock lock = new ReentrantLock();
        Condition c1 = lock.newCondition();
        Condition c2 = lock.newCondition();

        // c1和c2是两个对象
        assert c1 != c2;
        var map = new ConcurrentHashMap<Integer, Integer>();

        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                map.put(i, i);
            }
        }).start();

        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                map.clear();
                System.out.flush();
                System.out.println("clear map" + map);
                System.out.flush();
            }
        }).start();

    }


    /**
     *
     */
    @Test(invocationCount = 1)
    public void t10() {

        int size = 80000;
        var map = new ConcurrentHashMap<Integer, Integer>();
//        for (int j = 0; j < 10; j++) {
        new Thread(() -> {
            for (int i = 0; i < size; i++) {
//                    MathUtil.resolvePrime();
                map.put(i, i);
            }
            System.out.println("put done");
        }).start();

        new Thread(() -> {
            if (map.isEmpty()) {
                System.out.println("empty map");
            } else {
                System.out.println("size is " + map.size());
            }

        }).start();

    }
    public static void main(String[] args) {
//        var map = new ConcurrentHashMap<Integer, Integer>();
//
//        ReentrantLock lock = new ReentrantLock();
//        Condition c1 = lock.newCondition();
//        Condition c2 = lock.newCondition();
//
//        assert c1 != c2;
//
//        new Thread(() -> {
//            for (int i = 0; i < 1000; i++) {
//                map.put(i * 312, i);
//            }
//        }).start();
//
//        new Thread(() -> {
//            for (int i = 0; i < 1000; i++) {
//                map.clear();
//                System.out.println("clear map" + map);
//            }
//        }).start();


//        }


    }

}
